/*
 *  Copyright (C) 2011 Jaime Pavlich-Mariscal
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package cl.ucn.disc.biblio.refcluster.control;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.PropertyException;

import org.apache.log4j.Logger;

import cl.ucn.disc.biblio.refcluster.clustering.ClusterManager;
import cl.ucn.disc.biblio.refcluster.reference.Author;
import cl.ucn.disc.biblio.refcluster.reference.Configuration;
import cl.ucn.disc.biblio.refcluster.reference.Reference;
import cl.ucn.disc.biblio.refcluster.reference.ReferenceManager;

public class ReferenceClustererController {

	public static final Logger LOGGER = Logger.getLogger(ReferenceClustererController.class.getName());

	private ClusterManager cm = new ClusterManager();
	private ReferenceManager rm = new ReferenceManager();

	private Configuration config;



	public ReferenceClustererController() {
		try {
			config = new Configuration();
		} catch (PropertyException e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	//****************************************
	// Configuration parameters

	public boolean getDisambiguateAuthors() {
		return Boolean.valueOf(config.getProperty(Configuration.AUTHORS_DISAMBIGUATE));
	}

	public synchronized void setDisambiguateAuthores(boolean disambiguateAuthors) {
		config.setProperty(Configuration.AUTHORS_DISAMBIGUATE, String.valueOf(disambiguateAuthors));
	}

	public synchronized String getBiblioDBSourceFolder() {
		return config.getProperty(Configuration.BIBLIO_DB_SOURCE_FOLDER);
	}

	public synchronized void setBiblioDBSourceFolder(String biblioDBSourceFolder) {
		config.setProperty(Configuration.BIBLIO_DB_SOURCE_FOLDER, biblioDBSourceFolder);
	}

	public synchronized String getBiblioDBDestFolder() {
		return config.getProperty(Configuration.BIBLIO_DB_DESTINATION_FOLDER);
	}

	public synchronized void setBiblioDBDestFolder(String biblioDBDestFolder) {
		config.setProperty(Configuration.BIBLIO_DB_DESTINATION_FOLDER, biblioDBDestFolder);
	}

	public synchronized String getAuthorClustersFilename() {
		return config.getProperty(Configuration.AUTHOR_CLUSTER_FILENAME);
	}

	public synchronized void setAuthorClustersFilename(String authorClustersFilename) {
		config.setProperty(Configuration.AUTHOR_CLUSTER_FILENAME, authorClustersFilename);
	}

	public synchronized String getReferenceClustersFilename() {
		return config.getProperty(Configuration.REFERENCE_CLUSTER_FILENAME);
	}

	public synchronized void setReferenceClustersFilename(String referenceClustersFilename) {
		config.setProperty(Configuration.REFERENCE_CLUSTER_FILENAME, referenceClustersFilename);
	}

	public synchronized void saveConfig() throws PropertyException {
		config.save();
	}

	//***********************************
	// Controller methods
	
	public synchronized void createReferenceClusterFileFromWoSFolder(File wosDBFolder, File referenceClusterFile) throws IOException {
		LOGGER.info("BEGIN creating reference clusters...");
		Set<Reference> refs = rm.readRefsFromWoSFolder(wosDBFolder);
		Set<Set<Reference>> clusters = cm.clusterReferences(refs);
		LOGGER.info("References clustered...");
		cm.writeReferenceClusters(clusters, new PrintWriter(referenceClusterFile));
		LOGGER.info("FINISHED: Reference clusters written to " + wosDBFolder.getCanonicalPath());

	}

	public synchronized void createAuthorClusterFileFromWoSFolder(File wosDBFolder, File authorClusterFile) throws IOException, SecurityException, NoSuchFieldException {
		LOGGER.info("BEGIN creating author clusters...");
//		Set<Reference> refs = rm.readRefsFromWoSFolder(wosDBFolder);
//		Set<Author> authors = Utils.projection(refs, Reference.class.getDeclaredField("author"), HashSet.class, Author.class);
		LOGGER.info("Reading authors from " + wosDBFolder.getAbsolutePath()+ "...");
		Set<Author> authors = rm.readAuthorsFromWoSFolder(wosDBFolder);
		
		LOGGER.info("Clustering authors...");
		Set<Set<Author>> clusters = cm.clusterAuthors(authors);
		LOGGER.info("Authors clustered...");
		cm.writeAuthorClusters(clusters, new PrintWriter(authorClusterFile));
		LOGGER.info("FINISHED: Author clusters written to " + wosDBFolder.getCanonicalPath());
	}

	public synchronized void replaceReferencesAndAuthorsOfFolder(File srcFolder, File destFolder, File clusterFile, File authorClusterFile) throws Exception {
		LOGGER.info("BEGIN creating new database...");
		Collection<Set<Reference>> referenceClusters = cm.readClusters(clusterFile, Reference.class);
		Map<Reference, String> referenceReplacements = cm.getReferenceReplacementsFromClusters(referenceClusters);
		rm.replaceReferencesOfWoSFolder(srcFolder, destFolder, referenceReplacements);
		if (authorClusterFile != null) {
			Collection<Set<Author>> authorClusters = cm.readClusters(authorClusterFile, Author.class);
			Map<Author, String> authorReplacements = cm.getAuthorReplacementsFromClusters(authorClusters);
			rm.replaceAuthorsOfWoSFolder(destFolder, destFolder, authorReplacements);
		}
		LOGGER.info("FINISHED: New database written to " + destFolder.getCanonicalPath());
	}
	

}
